<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\analysis\data\account;

use app\model\mongo\MongoClientAccountTypeDayStatModel;
use app\model\mongo\MongoClientMediaMonthStatModel;
use app\model\mongo\MongoStatModel;
use app\service\BaseService;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

/**
 * 账户-按客户+媒体+月份汇总.
 */
final class ClientMediaMonthStatService extends BaseService
{
    /**
     * @var null|MongoClientAccountTypeDayStatModel 产品日汇总模型
     */
    private ?MongoClientAccountTypeDayStatModel $model;

    /**
     * @var int 汇总月份
     */
    private int $statMonth = 0;

    public function __construct()
    {
    }

    /**
     * 获取数据列表.
     *
     * @return array|Collection|MongoClientAccountTypeDayStatModel[]
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getList()
    {
        return (new MongoClientAccountTypeDayStatModel())
            ->where('is_change', '=', MongoStatModel::IS_CHANGE_YES)
            ->page(1)
            ->limit(10)
            ->select();
    }

    /**
     * 执行任务
     */
    public function runTask(MongoClientAccountTypeDayStatModel $model): bool
    {
        $this->model = $model;
        if (! $this->model->getKey()) {
            return self::setError('未知客户日汇总');
        }
        $this->getMonth();
        if (! $this->setStat()) {
            return false;
        }
        return $this->finishLog();
    }

    /**
     * 初始化汇总月份.
     */
    protected function getMonth()
    {
        $this->statMonth = intval(date('Ym', strtotime(strval($this->model->getAttr('stat_date')))));
    }

    /**
     * 设置汇总数据.
     */
    private function setStat(): bool
    {
        $model = $this->getStatModel();
        if (! $model->getKey()) {
            $data = [
                'company_id' => $this->model->getAttr('company_id'),
                'client_id' => $this->model->getAttr('client_id'),
                'media_id' => $this->model->getAttr('media_id'),
                'stat_month' => $this->statMonth,
                'is_change' => MongoStatModel::IS_CHANGE_YES,
            ];
        } else {
            $data = [
                'is_change' => MongoStatModel::IS_CHANGE_YES,
            ];
        }
        $data = $this->getStatField($data);
        $model->setAttrs($data);
        if (! $model->save()) {
            return self::setError('保存汇总数据失败');
        }
        return true;
    }

    /**
     * 获取汇总模型.
     *
     * @return array|mixed|Model|MongoClientMediaMonthStatModel
     */
    private function getStatModel()
    {
        return (new MongoClientMediaMonthStatModel())
            ->where([
                'company_id' => $this->model->getAttr('company_id'),
                'client_id' => $this->model->getAttr('client_id'),
                'media_id' => $this->model->getAttr('media_id'),
                'stat_month' => $this->statMonth,
            ])
            ->findOrEmpty();
    }

    /**
     * 获取汇总字段值
     * @param array $data 数据值
     */
    private function getStatField(array $data = []): array
    {
        $model = new MongoClientAccountTypeDayStatModel();
        $res = $model->cmd([
            'aggregate' => $model->getTable(),
            'pipeline' => [
                [
                    '$match' => [
                        'company_id' => $this->model->getAttr('company_id'),
                        'client_id' => $this->model->getAttr('client_id'),
                        'media_id' => $this->model->getAttr('media_id'),
                        'stat_date' => [
                            '$gte' => intval($this->statMonth . '01'),
                            '$lte' => intval($this->statMonth . '31'),
                        ],
                    ],
                ],
                [
                    '$group' => [
                        '_id' => null,
                        'totalCost' => ['$sum' => '$cost'],
                        'totalBalance' => ['$sum' => '$balance'],
                        'totalCashCost' => ['$sum' => '$cash_cost'],
                        'totalRewardCost' => ['$sum' => '$reward_cost'],
                    ],
                ],
                [
                    '$project' => [
                        '_id' => 1,
                        'totalCost' => 1,
                        'totalBalance' => 1,
                        'totalCashCost' => 1,
                        'totalRewardCost' => 1,
                    ],
                ],
            ],
            'cursor' => new \stdClass(),
            'explain' => false,
        ]);
        $stat = $res[0] ?? [];
        $data['cost'] = $stat['totalCost'] ?? 0;
        $data['balance'] = $stat['totalBalance'] ?? 0;
        $data['cash_cost'] = $stat['totalCashCost'] ?? 0;
        $data['reward_cost'] = $stat['totalRewardCost'] ?? 0;
        return $data;
    }

    /**
     * 设置日志汇总状态
     */
    private function finishLog(): bool
    {
        $this->model->setAttr('is_change', MongoStatModel::IS_CHANGE_NO);
        return $this->model->save();
    }
}
